﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NumericalData.DifferentialEquations;
using info.lundin.math;

namespace NumericalData.DifferentialEquations.Data
{
    public class ODESystemContainer
    {
        #region Properties

        public int Dimensionality { get; private  set; }
        public double TimeIntervalStart { get; private set; }
        public double TimeIntervalStop { get; private set; }
        #endregion

        #region Constructors

        public ODESystemContainer(int dim, double start, double stop)
        {
            Dimensionality = dim;
            TimeIntervalStart = start;
            TimeIntervalStop = stop;
        }
        #endregion

    }

    public class CauchyProblemContainer : ODESystemContainer
    {
        #region Fields

        private ExpressionParser _parser;
        private List<string> _expressions;
        private Hashtable _values;
        #endregion

        #region Properties

        public VectorFunction RightPartsVectorFunction { get; private set; }
        public Vector StartValues { get; private set; }
        public bool SystemIsValid { get; private set; }
        public string StateMessage { get; private set; }
        #endregion

        #region Constructors
        
        public CauchyProblemContainer(List<string> systemRightParts, List<double> startValues, double timeStart, double timeStop  )
            :base(systemRightParts.Count,timeStart,timeStop)
        {
            if (systemRightParts.Count != startValues.Count)
            {
                SystemIsValid = false;
                StateMessage = "Number of equations do not stack with number of start values";
                return;
            }
            _expressions = systemRightParts;
            StartValues = new Vector(startValues.ToArray());
            InitializeComponent();
        }
        #endregion

        #region Methods
        
        private void InitializeComponent()
        {
            _parser = new ExpressionParser();
            RightPartsVectorFunction = Evaluator;
            SystemIsValid = true;
            StateMessage = "valid";
        }

        private Vector Evaluator(double t, Vector yValues)
        {
            if (!SystemIsValid)
                throw new Exception("Function executed from invalid container");

            if(yValues.Length != Dimensionality)
                throw new Exception("Values vector has wrong length");

            if(t<TimeIntervalStart||t>TimeIntervalStop+t/100)
                throw new Exception("t parameter is out of initial range");

            SetVariablesValues(t,yValues);

            return GetAnswerVector();
        }

        private void SetVariablesValues(double t, Vector yValues)
        {
            _values = new Hashtable();
            _values.Add("t",t.ToString());
            for (var i = 0; i < yValues.Length; ++i)
                _values.Add("y" + (i + 1), yValues[i].ToString());
        }

        private Vector GetAnswerVector()
        {
            double[] values = new double[Dimensionality];
            for (var i = 0; i < Dimensionality; ++i)
                values[i] = _parser.Parse(_expressions[i], _values);
            return new Vector(values);
        }
        #endregion
    }




}
